<template>
    <div class="custom-upload">
        <a-upload
            v-bind="uploadProps"
            :file-list="fileList"
            :before-upload="beforeUpload"
            @change="handleChange"
            :disabled="disabled"
        >
            <slot name="upload-button">
                <a-button :disabled="disabled">
                    <upload-outlined></upload-outlined>
                    {{ buttonText }}
                </a-button>
            </slot>
        </a-upload>

        <!-- 文件列表显示 -->
        <div v-if="showFileList && fileList.length > 0" class="file-list">
            <div v-for="file in fileList" :key="file.uid || file.name" class="file-item">
                <span class="file-name" @click="previewFile(file)">
                    {{ file.name }}
                </span>
                <div class="file-actions">
                    <a-button type="link" size="small" @click="downloadFile(file)" v-if="showDownload"> 下载 </a-button>
                    <a-button type="link" size="small" @click="removeFile(file)" :disabled="disabled"> 删除 </a-button>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { UploadOutlined } from "@ant-design/icons-vue";
import type { UploadFile, UploadProps } from "ant-design-vue";
import { computed, ref, watch } from "vue";

interface Props {
    modelValue?: string | string[]; // 文件路径，可以是单个路径或路径数组
    maxCount?: number; // 最大上传数量
    accept?: string; // 允许的文件类型
    maxSize?: number; // 单个文件最大大小(MB)
    multiple?: boolean; // 是否支持多选
    disabled?: boolean; // 是否禁用
    showFileList?: boolean; // 是否显示文件列表
    showDownload?: boolean; // 是否显示下载按钮
    listType?: "text" | "picture" | "picture-card"; // 文件列表样式
    customRequest?: (options: any) => void; // 自定义上传请求
    buttonText?: string; // 按钮文字
    previewHandler?: (file: UploadFile) => void; // 预览处理函数
    downloadHandler?: (file: UploadFile) => void; // 下载处理函数
}

const props = withDefaults(defineProps<Props>(), {
    maxCount: 1,
    maxSize: 10, // 10MB
    multiple: false,
    disabled: false,
    showFileList: true,
    showDownload: false,
    listType: "text",
    buttonText: "选择文件"
});

const emit = defineEmits<{
    "update:modelValue": [value: string | string[]];
    change: [fileList: UploadFile[], file: UploadFile];
    remove: [file: UploadFile];
}>();

// 文件列表
const fileList = ref<UploadFile[]>([]);

// 合并上传组件属性
const uploadProps = computed<UploadProps>(() => ({
    multiple: props.multiple,
    maxCount: props.maxCount,
    accept: props.accept,
    customRequest: props.customRequest
    // 可以在这里添加其他需要的配置
    // 如 action, headers, data 等
}));

// 监听 modelValue 变化，同步文件列表
watch(
    () => props.modelValue,
    newVal => {
        if (!newVal) {
            fileList.value = [];
            return;
        }

        const paths = Array.isArray(newVal) ? newVal : [newVal];
        fileList.value = paths.map((path, index) => ({
            uid: `file-${index}-${Date.now()}`,
            name: path.split("/").pop() || "unknown-file",
            status: "done",
            url: path,
            response: { url: path } // 假设后端返回的url字段
        }));
    },
    { immediate: true }
);

// 上传前检查
const beforeUpload = (file: RcFile) => {
    // 检查文件大小
    const isLtSize = file.size / 1024 / 1024 < props.maxSize;
    if (!isLtSize) {
        // 这里可以使用 antd 的 message 组件显示错误信息
        console.error(`文件大小不能超过 ${props.maxSize}MB!`);
        return false;
    }

    // 检查文件类型
    if (props.accept) {
        const acceptTypes = props.accept.split(",").map(type => type.trim());
        const fileType = file.type || file.name.split(".").pop();
        const isAccepted = acceptTypes.some(acceptType => {
            if (acceptType.startsWith(".")) {
                // 文件扩展名检查
                return file.name.toLowerCase().endsWith(acceptType.toLowerCase());
            } else {
                // MIME 类型检查
                return file.type?.startsWith(acceptType.split("/")[0]);
            }
        });

        if (!isAccepted) {
            console.error(`不支持的文件类型!`);
            return false;
        }
    }

    return true;
};

// 文件状态改变
const handleChange: UploadProps["onChange"] = ({ fileList: newFileList, file }) => {
    fileList.value = newFileList;

    // 提取文件路径
    const filePaths = newFileList.filter(f => f.status === "done" && f.response?.url).map(f => f.response.url);

    // 根据单选或多选返回不同格式
    const result = props.multiple ? filePaths : filePaths[0] || "";
    emit("update:modelValue", result);
    emit("change", newFileList, file);
};

// 删除文件
const removeFile = (file: UploadFile) => {
    const index = fileList.value.findIndex(f => f.uid === file.uid);
    if (index > -1) {
        fileList.value.splice(index, 1);

        // 更新 modelValue
        const filePaths = fileList.value.filter(f => f.status === "done" && f.response?.url).map(f => f.response.url);

        const result = props.multiple ? filePaths : filePaths[0] || "";
        emit("update:modelValue", result);
        emit("remove", file);
    }
};

// 预览文件
const previewFile = (file: UploadFile) => {
    if (props.previewHandler) {
        props.previewHandler(file);
    } else {
        // 默认预览行为，可以打开新窗口或使用预览组件
        if (file.url) {
            window.open(file.url, "_blank");
        }
    }
};

// 下载文件
const downloadFile = (file: UploadFile) => {
    if (props.downloadHandler) {
        props.downloadHandler(file);
    } else {
        // 默认下载行为
        if (file.url) {
            const link = document.createElement("a");
            link.href = file.url;
            link.download = file.name;
            link.click();
        }
    }
};
</script>

<style scoped>
.custom-upload {
    width: 100%;
}

.file-list {
    margin-top: 8px;
}

.file-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 4px 0;
    border-bottom: 1px solid #f0f0f0;
}

.file-name {
    cursor: pointer;
    color: #1890ff;
    flex: 1;
}

.file-name:hover {
    text-decoration: underline;
}

.file-actions {
    display: flex;
    gap: 8px;
}

.file-actions .ant-btn {
    padding: 0 4px;
    height: 22px;
}
</style>
